package com.such.kit.file.bean;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import com.such.kit.file.FileCommons;
import com.such.kit.stream.StreamCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @author SUCH
 * <pre>
 * 通用的文件信息类
 * </pre>
 */
public class FileInfo implements Serializable {

	private static final long serialVersionUID = -2250749935626235252L;

	/** path：完整路径（包括文件名） */
	private String path;
	/** parentPath：父级路径 */
	private String parentPath;
	/** pathNavigation：路径导航，按路径分隔符将路径节点按顺序拆分到集合中 */
	private List<String> pathNavigation;
	/** name：文件名 */
	private String name;
	/** type：文件类型（扩展名） */
	private String type;
	/** size：文件大小（byte） */
	private long size;
	/** lastModified：最后修改时间 */
	private Date lastModified;
	/** isDirectory：是否为目录 */
	private boolean isDirectory = false;
	/** isHidden：是否为隐藏文件 */
	private boolean isHidden = false;
	/** canRead：是否可读 */
	private boolean canRead = false;
	/** canWrite：是否可写 */
	private boolean canWrite = false;
	/** canExecute：是否可执行 */
	private boolean canExecute = false;
	/** isEntry：是否为包（zip、jar）中的条目 */
	private boolean isEntry = false;
	/** packageFile：条目所在包 */
	private FileInfo packageFile;

	/**
	 * @param path 完整路径（包括文件名）
	 */
	public FileInfo(String path) {
		setPath(path);
	}

	/**
	 * @param path 完整路径（包括文件名）
	 * @param size 文件大小（byte）
	 * @param lastModified 最后修改时间
	 */
	public FileInfo(String path, long size, Date lastModified) {
		this(path);
		this.size = size;
		this.lastModified = lastModified;
	}

	/**
	 * @param file 文件
	 */
	public FileInfo(File file) {
		this(file.getAbsolutePath(), file.length(), new Date(file.lastModified()));
		setAttribute(file.isDirectory(), file.isHidden(), file.canRead(), file.canWrite(), file.canExecute());
	}

	/**
	 * <pre>
	 * [参考 {@link #FileInfo(String, String, String)}]
	 * 
	 * charset 默认为 {@link StringCommons#CHARSET_UTF8 UTF-8}
	 * </pre>
	 */
	public FileInfo(String packagePath, String entryName) {
		this(packagePath, StringCommons.CHARSET_UTF8, entryName);
	}

	/**
	 * @param packagePath 包的绝对路径
	 * @param charset 字符集
	 * @param entryName 条目名
	 */
	public FileInfo(String packagePath, String charset, String entryName) {
		this(entryName);
		File packageFile = new File(packagePath);
		ZipFile zipFile = null;
		try {
			zipFile = new ZipFile(packageFile, charset);

			ZipArchiveEntry zipEntry = zipFile.getEntry(entryName);
			setAttribute(zipEntry.isDirectory(), false, true, false, false);
			this.size = zipEntry.getSize();
			this.lastModified = new Date(zipEntry.getLastModifiedTime().toMillis());
			this.isEntry = true;
			this.packageFile = new FileInfo(packageFile);
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			StreamCommons.closePure(zipFile);
		}
	}

	/**
	 * @param zipPath zip 文件路径
	 * @param zipEntry zip 条目
	 */
	public FileInfo(String zipPath, ZipArchiveEntry zipEntry) {
		this(zipEntry.getName(), zipEntry.getSize(), new Date(zipEntry.getLastModifiedTime().toMillis()));
		setAttribute(zipEntry.isDirectory(), false, true, false, false);
		this.isEntry = true;
		this.packageFile = new FileInfo(new File(zipPath));
	}

	private void setPath(String path) {
		this.path = FileCommons.changeCompatSeparator(path);
		this.parentPath = FileCommons.cutLastPathNode(path);
		if (ValidateCommons.isNotEmpty(this.path)) {
			this.pathNavigation = Arrays.stream(this.path.split(FileCommons.COMPAT_SEPARATOR)).collect(Collectors.toList());
			this.name = this.pathNavigation.get(this.pathNavigation.size() - 1);
			this.type = FileCommons.getEnlargeName(this.name);
		}
	}

	/** [参考 {@link #path}] */
	public String getPath() {
		return this.path;
	}

	/** [参考 {@link #parentPath}] */
	public String getParentPath() {
		return this.parentPath;
	}

	/** [参考 {@link #pathNavigation}] */
	public List<String> getPathNavigation() {
		return this.pathNavigation;
	}

	/** [参考 {@link #name}] */
	public String getName() {
		return this.name;
	}

	/** [参考 {@link #type}] */
	public String getType() {
		return this.type;
	}

	/** [参考 {@link #size}] */
	public long getSize() {
		return this.size;
	}

	/** [参考 {@link #lastModified}] */
	public Date getLastModified() {
		return this.lastModified;
	}

	/** [参考 {@link #isDirectory}] */
	public boolean isDirectory() {
		return this.isDirectory;
	}

	/** [参考 {@link #isHidden}] */
	public boolean isHidden() {
		return this.isHidden;
	}

	/** [参考 {@link #canRead}] */
	public boolean isCanRead() {
		return this.canRead;
	}

	/** [参考 {@link #canWrite}] */
	public boolean isCanWrite() {
		return this.canWrite;
	}

	/** [参考 {@link #canExecute}] */
	public boolean isCanExecute() {
		return this.canExecute;
	}

	/** [参考 {@link #isEntry}] */
	public boolean isEntry() {
		return this.isEntry;
	}

	/** [参考 {@link #packageFile}] */
	public FileInfo getPackageFile() {
		return this.packageFile;
	}

	public void setAttribute(boolean isDirectory, boolean isHidden, 
			boolean canRead, boolean canWrite, boolean canExecute) {
		this.isDirectory = isDirectory;
		this.isHidden = isHidden;
		this.canRead = canRead;
		this.canWrite = canWrite;
		this.canExecute = canExecute;

		if (isDirectory) {
			this.type = null;
		}
	}

}
